#ifndef _READ_VIDEO_2_H_
#define _READ_VIDEO_2_H_

#include <sys/time.h>
#include <unistd.h>
#include <sys/select.h>

#include "read_video.h"
#include "options.h"
#include "frame_header.hh"
#include "other_functions.h"
#include <colores.h>

#include "Producer.hpp"


typedef struct {
    IplImage * left;
    frame_header *hleft;
    IplImage * right;
    frame_header *hright;
} _stereo_IplImage_t;

//typedef _stereo_IplImage_t T;
typedef int T;

class readthread : public CProducer<T>
{
 private:
    char *videoI_name;
    char *videoD_name;
    int iniframe;
    int frame;
    unsigned long readImageSize;
    FILE *rawvideo;
    FILE *rawvideo2;
    CvSize video_size;
    CvSize video_size2;
    CvSize video_size0;
    int video_channels;
    int difft;
	

 public: 
    typedef T value_type;
    
 readthreaddthread(bounded_buffer<T>::size_type capacity): CProducer<T>(capacity)
    {
	videoI_name =0;
	videoD_name=0;
	iniframe=0;
	frame=0;
    }
    ~readthread()
    {
    }

    /*bool start()
      {
      //Crea el hilo
      return CProducer<T>::start();
      }*/
    void stop()
    {
	CProducer<T>::stop();
    }
    T consumer()
    {
	return CProducer<T>::consumer();
    }

    //hilo de lectura
    void operator()()
    {
	int i;
	stereo_IplImage_t buffer_imgs[BUFFER_IMAGES];
	stereo_IplImage_t *imgs;

	//toma el nombre de los archivos a leer
	if (!videoI_name)
	    if (!get_video_names())
		return false;
	
	frame_header head, head2;

	//abre los archivos con los videos y lee las dos primeras imágenes
	rawvideo = fopen(p->videoI_name, "r");
	rawvideo2 = fopen(p->videoD_name, "r");

	fread(&head, sizeof(frame_header), 1, rawvideo);
	video_size.width = head.width;
	video_size.height = head.height;

	fread(&head2, sizeof(frame_header), 1, rawvideo2);
	video_size2.width = head2.width;
	video_size2.height = head2.height;
	
	printf("Video left:  width: %d, height: %d\n", video_size.width, video_size.height);
	printf("Video right: width: %d, height: %d\n", video_size2.width, video_size2.height);
	fflush(stdout);
	video_channels = 1;
	
	readImageSize = video_size.width * video_size.height;
	readImageSize2 = video_size2.width * video_size2.height;

	//elimina las imágenes que no valgan al principio del video
	if (iniframe == 0)
	{
	    while (head.nframe > 1)
	    {	
		fseeko(rawvideo, readImageSize- sizeof(head), SEEK_CUR);
		fread(&head, sizeof(frame_header), 1, rawvideo);
		printf("Video 1, Skipping frame %d\n", head2.nframe);
	    }   
	    while (head2.nframe > 1)
	    {
		fseeko(rawvideo2, readImageSize- sizeof(head2), SEEK_CUR);
		fread(&head2, sizeof(frame_header), 1, rawvideo2);
		printf("Video 2, Skipping frame %d\n", head2.nframe);
	    }   
	    //se coloca en el primer frame a leer
	    fseeko(rawvideo, - sizeof(head), SEEK_CUR);
	    fseeko(rawvideo2, - sizeof(head2), SEEK_CUR);
	}
	else
	{
	    //se coloca en el primer frame a leer
	    fseeko(rawvideo, readImageSize*p->iniframe, SEEK_SET);
	    fseeko(rawvideo2, readImageSize*p->iniframe, SEEK_SET);
	}

	//mete en el buffer el pimer set de imágenes, y desbloquea el semáforo
	//crea las dos primeras imágenes
	buffer_imgs[0].left = cvCreateImage(video_size0, IPL_DEPTH_8U, video_channels );
	buffer_imgs[0].right = cvCreateImage(video_size0, IPL_DEPTH_8U, video_channels );
	p->buffer_IplImage_free.push(&buffer_imgs[0]);

	//espera un poco para la inicialización del resto de cosas
	usleep(2000);

	//genera el buffer de imágenes donde leer del archivo
	for (i = 1; i<BUFFER_IMAGES; i++)
	{
	    buffer_imgs[i].left = cvCreateImage(video_size0, IPL_DEPTH_8U, video_channels );
	    buffer_imgs[i].right = cvCreateImage(video_size0, IPL_DEPTH_8U, video_channels );
	    p->buffer_IplImage_free.push(&buffer_imgs[i]);
	    p->free++;
	}
    

	// bucle que va leyendo las imágenes y dejándolas en el buffer
	while (!p->quit)
	{
	    //espera a que puede ejecutar la tarea
	    //pthread_mutex_lock(&mutex_read);

	    //si no hay buffer disponible, no lee, y espera a que haya
	    while (p->buffer_IplImage_free.empty())
	    {
		//pthread_mutex_unlock(&mutex_read);
		usleep(100000);
		//pthread_mutex_lock(&mutex_read);
	    }

	
	    //ya hay buffer libre. Coge el siguiente disponible
	    pthread_mutex_lock(&p->mutex_free);
	    imgs = p->buffer_IplImage_free.front();
	    p->buffer_IplImage_free.pop();
	    p->free--;
	    pthread_mutex_unlock(&p->mutex_free);

	    //lee las imágenes del fichero
	    imgs->hleft = read_image(imgs->left, rawvideo, video_size);
	    imgs->hright = read_image(imgs->right, rawvideo2, video_size);
	    difft = (int)difftime_ms(imgs->hleft->filltime, imgs->hright->filltime);
	    while (abs(difft) > 15)
	    {
		if (difft > 0)
		    imgs->hright = read_image(imgs->right, rawvideo2, video_size);
		else 
		    imgs->hleft = read_image(imgs->left, rawvideo, video_size);

		difft = (int)difftime_ms(imgs->hleft->filltime, imgs->hright->filltime);

		if (feof(rawvideo) || feof(rawvideo2))
		{
		    printf("End of video\n");
		    fflush(stdout);
		    p->quit = 1;
		    break;
		}
	    }
	    
	    if (p->quit)
		break;
	    //mete en buffer en la pila para que sea usado por el hilo consumidor
	    pthread_mutex_lock(&p->mutex_use);
	    p->buffer_IplImage_use.push(imgs);
	    p->use++;
	    pthread_mutex_unlock(&p->mutex_use);

	    //introduce un pequeño retardo en la lectura de imágnes
	    //pthread_mutex_unlock(&mutex_read);
	    usleep(500);
	}

    
	while (!p->buffer_IplImage_use.empty())
	{
	    usleep(10000);
	}

	for (i = 0; i<BUFFER_IMAGES; i++)
	{
	    cvReleaseImage(&buffer_imgs[i].left);
	    cvReleaseImage(&buffer_imgs[i].right);
	}

	if (videoI)
	    cvReleaseCapture(&videoI);
	if (videoD)
	    cvReleaseCapture(&videoD);
	if (rawvideo)
	    fclose(rawvideo);

	if (p->videoI_name)
	    free(p->videoI_name);
	if (p->videoD_name)
	    free(p->videoD_name);

	printf("fin de la captura de video\n");
	fflush(stdout);
	return NULL;

	//CProducer<T>::operator()();
    }
    void calll()
    {

    }

    bool get_video_names()
    {
	= (char *)malloc(strlen(video_name)+20);
	strcpy(p->videoI_name, video_name);
	p->videoD_name = 0;

	char *extension = rindex(p->videoI_name, '.');

	//busca el formato del archivo de video
	p->video_format = no_format;
	if (strcasecmp(format, "raw") == 0)
	{
	    p->video_format = raw_video;
	}
	else if (strcasecmp(format, "ra2") == 0)
	{
	    p->video_format = ra2_video;
	}
	else if (strcasecmp(format, "avi") == 0)
	{
	    p->video_format = avi_video;
	}
    
	if (p->video_format == no_format)
	{
	    if (extension == NULL)
		p->video_format = raw_video;
	    else if (strcasecmp(extension, ".cal") == 0)
		p->video_format = raw_video;
	    else if (strcasecmp(extension, ".avi") == 0)
		p->video_format = avi_video;
	    else if (strcasecmp(extension, ".raw") == 0)
		p->video_format = raw_video;
	    else if (strcasecmp(extension, ".ra2") == 0)
		p->video_format = ra2_video;
	    else
		p->video_format = no_format;
	}



	printf("video format: %d\n", p->video_format);
	//extrae los nombres de los videos, según el formato indicado

	switch (p->video_format)
	{
	case raw_video:
	    if (extension == NULL)
		strcat(p->videoI_name, "1.raw");
	    else if (strcasecmp(extension, ".cal") == 0)
		strcpy(extension, ".raw");

	    p->videoD_name = (char *)malloc(strlen(p->videoI_name)+20);
	    strcpy(p->videoD_name, p->videoI_name);
	    extension = rindex(p->videoD_name, '.');

	    if (extension[-1] == '2')
	    {
		extension = rindex(p->videoI_name, '.');
		extension[-1] = '1';
	    }
	    else
		extension[-1] = '2';
	    break;
	case ra2_video:
	    if (extension == NULL)
		strcat(p->videoI_name, ".ra2");
	    else if (strcasecmp(extension, ".cal") == 0)
		strcpy(extension, ".ra2");
	    break;

	case avi_video:
	    if (extension == NULL)
		strcat(p->videoI_name, "1.avi");
	    else if (strcasecmp(extension, ".cal") == 0)
		strcpy(extension, ".avi");
	    break;

	case no_format:
	    printf("Error de formato del video.\n");
	    free(p->videoI_name);
	    return 0;
	    break;
	}
    
	printf("Video 1:     %s\n", p->videoI_name);
	if (p->videoD_name)
	    printf("Video 2:     %s\n", p->videoD_name);
	
    }

    int get_ini_frame()
    {
	if (iniframe < 0)
	{
	    char buffer[400];
	    strcpy(buffer, p->videoI_name);
	    extension = rindex(buffer, '.');
	    strcpy(extension, ".ini");
	    FILE *fini = fopen(buffer, "r");
	    if (!fini)
		iniframe = 0;
	    else
	    {
		fscanf(fini, "%d", &iniframe);
		if (iniframe < 0) 
		    iniframe = 0;
	    }
	}
	p->iniframe = iniframe;
    }

};

#endif
